home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / Controls GH ƒ / Slider Control GH / Slider.c < prev    next >
C/C++ Source or Header  |  1994-04-23  |  25KB  |  910 lines

  1. #define __FOR__CDEV__
  2.  
  3. typedef pascal void (*IndicatorAction) (void);
  4.  
  5. /************** Slider.c v1.1 *********
  6. ******* code for a slider type control CDEF
  7. *******©1993 Glenn R. Howes
  8. ******* all rights reserved *****/
  9.  
  10. #include "utilities.h"
  11. pascal long main(short variation, ControlHandle me,
  12.                 short msg, long param)
  13. {
  14.     long result = 0L;
  15.  
  16.  
  17.     switch (msg)
  18.     {
  19.         case testCntl: // determine if mouse down is in control
  20.             result = TestMe(me, HiWord(param), LoWord(param));
  21.         break;
  22.         case calcCRgns: // 24-bit means of requesting shape of control or part
  23.             result = CalcStripRegion(me, (RgnHandle)param);
  24.         break;
  25.         case initCntl: // 1st message, allocate private data
  26.             InitMe(me);
  27.         break;
  28.         case dispCntl: // last message, dispose private data
  29.             if ((*me)->contrlData)
  30.                 DisposeHandle((*me)->contrlData);
  31.         break;
  32.         case posCntl: // given new point (and old point from the thumbCntl msg)
  33.                     // set the controls new value
  34.             PositionMe(me, HiWord(param), LoWord(param));
  35.         break;
  36.         case thumbCntl: // request for info for use in dragging thumb outline
  37.                         // also gives point at which drag starts
  38.             ProvideDragInfo(me, (ThumbInfo*)param);
  39.         break;
  40.         case dragCntl:
  41.             if (param)
  42.             {
  43.                 DragMe(me, LoWord(param));
  44.                 
  45. /************
  46. **    if we are being used by a CDEV or other modal dialog, we have to fool
  47. **  the dialog manager into sending the item hit message through to the application
  48. **  so, we return a 0 in those cases. We play around with other routines so that 
  49. **  the default dragging when it is called is invisible to the user.
  50. **  If we are being used by an application which can manually call TrackControl, we
  51. **  can do things the right way and just check the slider's value after the call
  52. **  to TrackControl. I suppose I ought to just have one version of this code and
  53. **  use variation codes, but that is neither here nor there.
  54. *************/
  55.  
  56.  
  57. #ifndef __FOR__CDEV__
  58.                 result = 1L;
  59. #endif
  60.             }
  61.         break;
  62.  
  63.         break;
  64.         case calcCntlRgn: // 32-bit clean message asking for whole cntl region
  65.             CalcRegion( me, (RgnHandle)param, FALSE);
  66.             result = 1L;
  67.         break;
  68.         case calcThumbRgn: // 32-bit clean message asking for shape of thumb
  69.             result =  CalcRegion( me, (RgnHandle)param, TRUE);
  70.             result =  1L;
  71.         break;
  72.         case drawCntl: // draw control or part of control
  73.             DrawMe(me, LoWord(param));
  74.         break;
  75.     }
  76.     
  77.     
  78.     return (result);
  79. }
  80. /********************** DragMe ******************
  81. ** Here's the situation, there has been a mouse down in my
  82. ** slider's thumb. I will move the thumb back & forth or
  83. ** up and down until the mouse is released. If there is a
  84. ** action proc, I will update the control's value and call it.
  85. ** If there is a proc stored in the low memory global DragHook,
  86. ** I'll call that too.
  87. ** 
  88. ** I've really violated the zeroth rule of programming
  89. ** "Never write the same code twice" here and I apologize. If I had
  90. ** the time I would modularize all the part drawing
  91. **************************************************/
  92. void DragMe(ControlHandle me, short part)
  93. {
  94.     Point            newPoint, lastPoint, offsetPoint;
  95.     unsigned long    currTime, lastTime, pinnedPoint;
  96.     Point            entry;
  97.     Rect            ctlRect, mouseRect, updateRect, newRect, lastRect;
  98.     Boolean            erase, fill,frame, vertical;
  99.     short            thumbLen, halfThumb;
  100.     short            diameter;
  101.     Pattern            grayPattern;
  102.     RgnHandle        savedClip = 0L, thumbRegion =0L, nonThumbRegion =0L;
  103.     Rect            bigRect;
  104.     IndicatorAction    action = (*me)->contrlAction;
  105.  
  106.     CopyRect(&(*me)->contrlRect, &ctlRect);
  107.     thumbLen = CalcThumbLen(&ctlRect);
  108.     halfThumb = thumbLen >> 1;
  109.     diameter = CalcRounding(&ctlRect);
  110.     GetMouse(&lastPoint);
  111.     CalcThumbRects(me, (*me)->contrlValue, &lastRect);
  112.     offsetPoint.h = lastPoint.h - lastRect.left;
  113.     offsetPoint.v = lastPoint.v - lastRect.top;
  114.     GetIndPattern(grayPattern, 0, 1);// standard black for frame and top region
  115.     vertical = ((ctlRect.bottom - ctlRect.top) // if we are a vertical control
  116.             >= (ctlRect.right - ctlRect.left));
  117.             
  118.     savedClip = NewRgn();
  119.     thumbRegion = NewRgn();
  120.     nonThumbRegion = NewRgn();
  121.     if (savedClip && thumbRegion && nonThumbRegion)
  122.     {
  123.         GetClip(savedClip);
  124.         OpenRgn();
  125.         FrameRoundRect(&lastRect, diameter, diameter);
  126.         CloseRgn(thumbRegion);
  127.         SetRect(&bigRect, -16000,-16000,16000,16000);
  128.         OpenRgn();
  129.         FrameRect(&bigRect);
  130.         CloseRgn(nonThumbRegion);
  131.         XorRgn(nonThumbRegion,thumbRegion,nonThumbRegion);
  132.         DisposeRgn(thumbRegion);
  133.         thumbRegion = 0L;
  134.     }
  135.     
  136.     while(WaitMouseUp())
  137.     {
  138.         erase = fill = frame = FALSE;
  139.         CalcThumbLen(&ctlRect);
  140.         GetMouse(&newPoint);
  141.         
  142.         
  143.         CopyRect(&ctlRect, &mouseRect);
  144.         CopyRect(&ctlRect, &updateRect);
  145.         CopyRect(&ctlRect, &newRect);
  146.  
  147.         if (vertical)
  148.         {
  149.             updateRect.left += 1;
  150.             updateRect.right -=1;
  151.             
  152.             mouseRect.top += offsetPoint.v;
  153.             mouseRect.bottom -= (thumbLen - offsetPoint.v);
  154.             *((long *)(&newPoint)) = PinRect(&mouseRect,newPoint);
  155.  
  156.             newRect.top = newPoint.v - offsetPoint.v;
  157.             newRect.bottom = newRect.top + thumbLen;
  158.  
  159.             if (newPoint.v == lastPoint.v) // haven't moved
  160.             {
  161.                 continue; // go back to WaitMouseUp
  162.             }
  163.             if (nonThumbRegion) // shift the mask to cover the new thumb rectangle
  164.                 OffsetRgn(nonThumbRegion,0,newPoint.v - lastPoint.v);
  165.                 
  166.             if (newPoint.v > lastPoint.v) // moved down
  167.             {
  168.                 fill = TRUE;
  169.                 updateRect.top = lastRect.top;
  170.                 updateRect.bottom = newRect.top + halfThumb;
  171.             }
  172.             else // moved up
  173.             {
  174.                 erase = TRUE;
  175.                 updateRect.bottom = lastRect.bottom;
  176.                 updateRect.top = newRect.bottom - halfThumb;
  177.                 if (lastRect.bottom >= ctlRect.bottom -4)
  178.                 {
  179.                     frame = TRUE;
  180.                 }
  181.             }
  182.             
  183.         }
  184.         else
  185.         {
  186.             updateRect.top += 1;
  187.             updateRect.bottom -=1;
  188.             
  189.             mouseRect.left += offsetPoint.h;
  190.             mouseRect.right -= (thumbLen - offsetPoint.h -1);
  191.             *((long *)(&newPoint))  = PinRect(&mouseRect,newPoint);
  192.  
  193.             newRect.left = newPoint.h - offsetPoint.h;
  194.             newRect.right = newRect.left + thumbLen;
  195.  
  196.             if (newPoint.h == lastPoint.h) // haven't moved
  197.             {
  198.                 continue; // go back to WaitMouseUp
  199.             }
  200.             
  201.             if (nonThumbRegion)
  202.                 OffsetRgn(nonThumbRegion,newPoint.h - lastPoint.h,0);
  203.             if (newPoint.h < lastPoint.h) // moved left
  204.             {
  205.                 fill = TRUE;
  206.                 updateRect.right = lastPoint.h - offsetPoint.h
  207.                                     + thumbLen;
  208.                 updateRect.left = newRect.left + halfThumb;
  209.             }
  210.             else // moved right
  211.             {
  212.                 erase = TRUE;
  213.                 updateRect.left = lastPoint.h - offsetPoint.h;
  214.                 updateRect.right = newRect.left + halfThumb;
  215.                 if (lastRect.left <= ctlRect.left + 4)
  216.                 {
  217.                     frame = TRUE;
  218.                 }
  219.             }
  220.         }
  221.         lastPoint.v = newPoint.v;
  222.         lastPoint.h = newPoint.h;
  223.         
  224.         lastTime = TickCount();
  225.         if (nonThumbRegion)
  226.             SetClip(nonThumbRegion);
  227.         do
  228.         {
  229.             currTime = TickCount();
  230.         }while (currTime == lastTime); // to avoid flicker drawing done at most once a tick
  231.         
  232.         if (erase)
  233.         {
  234.             EraseRect(&updateRect);
  235.         }
  236.         else if (fill)
  237.         {
  238.             
  239.             FillRoundRect(&updateRect,diameter, diameter, grayPattern);
  240.         }
  241.         
  242.         if (frame)
  243.         {
  244.             FrameRoundRect(&ctlRect, diameter,diameter);
  245.         }
  246.         if (savedClip)
  247.             SetClip(savedClip);
  248.         DrawMyIndicator(me, &newRect);
  249.         CopyRect(&newRect, &lastRect);
  250.         
  251.         
  252.         if (action && action != (ProcPtr) -1L)
  253.         {
  254.             newPoint.h = lastRect.left + halfThumb;
  255.             newPoint.v = lastRect.top + halfThumb;
  256.             MapPt2Value(me, &newPoint, &(*me)->contrlValue);
  257.             action();
  258.         }
  259.         
  260.         if (DragHook && DragHook != (ProcPtr) -1L) // DragHook is a low memory global
  261.         {
  262.             ((IndicatorAction) DragHook)();
  263.         }
  264.         
  265.     } 
  266.     // the user has let up on the mouse
  267.     // time to clean up
  268.     newPoint.h = lastRect.left + halfThumb;
  269.     newPoint.v = lastRect.top + halfThumb;
  270.     MapPt2Value(me, &newPoint, &(*me)->contrlValue);
  271.     if(savedClip)
  272.     {
  273.         SetClip(savedClip);
  274.         DisposeRgn(savedClip);
  275.     }
  276.     if (nonThumbRegion)
  277.         DisposeRgn(nonThumbRegion);
  278.     
  279.     DrawMe(me, 0); // snap the thumb into the nearest quantum
  280. }
  281. /******************* ProvideDragInfo ***********
  282. **** a mouse down has occurred in the thumb and we are
  283. **** asked to proide information used by the toolbox routine
  284. **** DragGrayRgn to confine the drag to a given rectangle 
  285. ****  the limit rect is the rect in which the region will move
  286. ****  the slop rect is the rect in which the mouse can be and the
  287. ****  gray outline will still be visible.
  288. ****  Notice that I'm taking into account the position within the
  289. ****  thumb so that the region doesn't go beyond the control****/
  290. void ProvideDragInfo(ControlHandle me, ThumbInfo *param)
  291.     Rect            ctlRect, thumbRect;
  292.     PrivateHandle    privData;
  293.     Point            entry;
  294.     privData = (PrivateHandle)(*me)->contrlData;
  295.     
  296.     // the original mousedown point is stored in the top,left corner of
  297.     // the thumbinfo's limitRect field
  298.     
  299.     entry.h = param->limitRect.left;
  300.     entry.v = param->limitRect.top;
  301.  
  302.     CopyRect(&(*me)->contrlRect, &ctlRect);
  303.     
  304.  
  305.     CalcThumbRects(me, (*me)->contrlValue, &thumbRect);
  306.     
  307.     if (privData)
  308.     {
  309.         (*privData)->lastPoint.h = entry.h;
  310.         (*privData)->lastPoint.v = entry.v;
  311.         (*privData)->offsetPoint.h = entry.h - thumbRect.left;
  312.         (*privData)->offsetPoint.v = entry.v - thumbRect.top;
  313.         CopyRect(&thumbRect, &(*privData)->lastRect);
  314.         (*privData)->lastTime = TickCount();
  315.     }
  316.     
  317.     
  318.     if ((ctlRect.bottom - ctlRect.top) // if we are a vertical control
  319.         >= (ctlRect.right - ctlRect.left))
  320.     {
  321.         ctlRect.bottom -= (thumbRect.bottom - entry.v);
  322.         ctlRect.top += (entry.v - thumbRect.top);
  323.         
  324.         CopyRect(&ctlRect, ¶m->limitRect);
  325.     
  326.         param->axis = 2; // confine to vertical
  327.     }
  328.     else // if we are a horizontal control
  329.     {
  330.         ctlRect.right -= (thumbRect.right - entry.h) -1;
  331.         ctlRect.left += (entry.h - thumbRect.left);
  332.         
  333.         CopyRect(&ctlRect, ¶m->limitRect);
  334.     
  335.         param->axis = 1; // confine to horizontal
  336.  
  337.     }
  338. /*******
  339. ** here's the scoop, if we are being used by a CDEV, or a modal dialog
  340. ** we have to force the dialog manager into recognizing that the thumb
  341. ** has been moved
  342. ***************/
  343.     #ifdef __FOR__CDEV__
  344.     SetRect(¶m->slopRect,-32000,-32000,32000,32000);
  345.     CopyRect(&(*me)->contrlRect, ¶m->limitRect);
  346.     return;
  347.     #endif
  348.     InsetRect(&ctlRect, -5, -5); // make slop bigger than ctl rect
  349.     CopyRect(&ctlRect, ¶m->slopRect);
  350. }
  351. /************ PositionMe *************
  352. ******** I've been dragged, with the sequence 
  353. ****** TestMe, ProvideDragInfo, and now PositionMe
  354. ****** so the delta values are changes from the original mousedown *****/
  355. void PositionMe(ControlHandle me, short deltaV, short deltaH)
  356. {
  357.     Point    newPoint;
  358. /******** 
  359. ** if we are using our own drag routines, we have already set the value of
  360. ** of the control, so we don't need to set it now.
  361. ********/
  362. #ifdef __FOR__CDEV__
  363.     return;
  364. #endif
  365.     MapValue2Point(me, (*me)->contrlValue, &newPoint);
  366.     newPoint.v += deltaV;
  367.     newPoint.h += deltaH;
  368.     
  369.     MapPt2Value(me, &newPoint, &(*me)->contrlValue);
  370.     DrawMe(me, 0);
  371. }
  372. /************ MapPt2Value *****************
  373. ***** given a point within the control, map it to a control value
  374. ******/
  375. void MapPt2Value(ControlHandle me, Point *aPoint, short *value)
  376. {
  377.     Rect    ctlRect;
  378.     short    width, height, thumbLen, halfThumb;
  379.     long    min, max, locValue;
  380.     
  381.     CopyRect(&(*me)->contrlRect, &ctlRect);
  382.     min = (*me)->contrlMin;
  383.     max = (*me)->contrlMax;
  384.     
  385.     width = ctlRect.right - ctlRect.left;
  386.     height = ctlRect.bottom - ctlRect.top;
  387.     
  388.     thumbLen = CalcThumbLen(&ctlRect);
  389.     halfThumb = thumbLen /2;
  390.     
  391.     if (width > height)
  392.     {
  393.         ctlRect.right -= halfThumb;
  394.         ctlRect.left += halfThumb;
  395.         width -= thumbLen;
  396.         if (ctlRect.right < aPoint->h) aPoint->h = ctlRect.right;
  397.         else if (ctlRect.left > aPoint->h) aPoint->h = ctlRect.left;
  398.     
  399.         locValue = min + ((max-min)*(aPoint->h-ctlRect.left))/width;
  400.     }
  401.     else
  402.     {
  403.         ctlRect.bottom -= halfThumb;
  404.         ctlRect.top += halfThumb;
  405.         height -= thumbLen;
  406.         if (ctlRect.bottom < aPoint->v) aPoint->v = ctlRect.bottom;
  407.         else if (ctlRect.top > aPoint->v) aPoint->v = ctlRect.top;
  408.         
  409.         locValue = min + ((max-min)*(ctlRect.bottom-aPoint->v))/height;
  410.     }
  411.     *value = locValue;
  412. }
  413. /*********** MapValue2Point *********
  414. ******* given a control value, convert it to a point within
  415. ******* the control corresponding to where the center of the thumb
  416. ******* must be **********/
  417. void MapValue2Point(ControlHandle me, short value, Point *aPoint)
  418. {
  419.     Rect    ctlRect;
  420.     long    width, height;
  421.     long    min, max;
  422.     short    thumbLen, halfThumb;
  423.     CopyRect(&(*me)->contrlRect, &ctlRect);
  424.     min = (*me)->contrlMin;
  425.     max = (*me)->contrlMax;
  426.     
  427.     thumbLen = CalcThumbLen(&ctlRect);
  428.     halfThumb = thumbLen /2;
  429.     
  430.     width = ctlRect.right - ctlRect.left;
  431.     height = ctlRect.bottom - ctlRect.top;
  432.     
  433.     if (value > max)
  434.         value = max;
  435.     else if (value < min) 
  436.         value = min;
  437.  
  438.     if (width > height) // horizontal control
  439.     {
  440.         width -= thumbLen;
  441.         aPoint->h = ctlRect.left + halfThumb + (width*value)/(max-min);
  442.         aPoint->v = ctlRect.top + height /2;
  443.     }
  444.     else
  445.     {
  446.         height -= thumbLen;
  447.         aPoint->v = ctlRect.bottom - halfThumb -(height * value)/(max-min);
  448.         aPoint->h = ctlRect.left + width /2;
  449.     }
  450. }
  451.  
  452. /************* CalcStripRegion *******
  453. ******* when in 24-bit mode, we will get a region handle whose
  454. ******* 31st bit is used to indicate if the app wants the region
  455. ******* of the thumb (on) or the whole control (off).
  456. ******* We are supposed to strip off the bit and return the 
  457. ******* calculated region ******/
  458. long CalcStripRegion(ControlHandle me, RgnHandle theRegion)
  459. {
  460.     char    calcThumb;
  461.     if (Using32Bit()) // WHY IS THIS GETTING CALLED¿
  462.     {
  463.         return (CalcRegion(me, theRegion, FALSE));
  464.     }
  465.     else
  466.     {
  467.         calcThumb = (long)theRegion >> 31L; // getting high bit, on = calc thumb
  468.         theRegion = (RgnHandle)(0x7FFFFFFFL & (long)theRegion); 
  469.         // stripping out high bit only see tech note “joy of 32 bit clean”
  470.         return (CalcRegion(me, theRegion, calcThumb)); // calc the region
  471.     }
  472. }
  473. /*************** CalcRegion ******
  474. ******* figure the region of the control, or the thumb if the 
  475. ******* calcThumb parameter is non-zero **********/
  476. long CalcRegion(ControlHandle me, RgnHandle theRegion, char calcThumb)
  477. {
  478.     RgnHandle    myRegion, curClip;
  479.     Rect        ctlRect, thumbRect;
  480.     short        diameter;
  481.     
  482. #ifdef __FOR__CDEV__
  483.     return ((long)theRegion);
  484. #endif
  485.     
  486.     CopyRect(&(*me)->contrlRect, &ctlRect);
  487.     
  488.     myRegion = NewRgn();
  489.     if(curClip = NewRgn())
  490.     {
  491.         GetClip(curClip);
  492.         ClipRect(&ctlRect);
  493.     }
  494.     
  495.     if (myRegion)
  496.     {
  497.         OpenRgn();
  498.         
  499.         diameter = CalcRounding(&ctlRect);
  500.         if (calcThumb)
  501.         {
  502.             CalcThumbRects(me, (*me)->contrlValue, &thumbRect);
  503.             FrameRoundRect(&thumbRect, diameter,diameter);
  504.         }
  505.         else
  506.         {
  507.             FrameRoundRect(&ctlRect, diameter, diameter);
  508.         }
  509.  
  510.         CloseRgn(myRegion);
  511.         InsetRgn(myRegion, -1, -1); // make it a little bigger to take into account
  512.                                     // width of lines
  513.         UnionRgn(theRegion, myRegion, theRegion);
  514.         DisposeRgn(myRegion);
  515.     }
  516.     if (curClip) 
  517.     {
  518.         SetClip(curClip);
  519.         DisposeRgn(curClip);
  520.     }
  521.     return ((long)theRegion);
  522. }
  523. /************ TestMe ****************
  524. ******* is the point within the control, and if so,
  525. ******* what part, there are 3 parts: thumb, pageup, 
  526. pagedown **********/
  527. long TestMe(ControlHandle me, short v, short h)
  528. {
  529.     Point            testPoint;
  530.     long            result = 0L;
  531.     Rect            ctlRect, whiteRect, grayRect, roundThumb;
  532.     
  533.     testPoint.h = h; testPoint.v = v;
  534.     
  535.     if(PtInRect(testPoint, &(*me)->contrlRect) && (*me)->contrlHilite < 255) 
  536.     // quick determination of (mouse in rect and control undimmed)
  537.     {
  538.         CopyRect(&(*me)->contrlRect, &ctlRect);
  539.         CalcGrayRect(me, &grayRect, &whiteRect);
  540.         CalcThumbRects(me,(*me)->contrlValue, &roundThumb);
  541.         if (PtInRect(testPoint, &roundThumb))
  542.         {
  543.             result = inThumb;
  544.         }
  545.         /*
  546.         else if (PtInRect(testPoint, &grayRect))
  547.         {
  548.             result = inPageUp;
  549.         }
  550.         else
  551.         {
  552.             result = inPageDown;
  553.         } */
  554.     }
  555.     return (result);
  556. }
  557. /*************** DrawMe **********
  558. ******* Draw the control or the control's thumb *****/
  559. void DrawMe(ControlHandle me, short part)
  560. {
  561.     Rect            grayRect, whiteRect, thumbRect, tempRect;
  562.     PenState        oldState;
  563.     PrivateHandle    privData;
  564.     RgnHandle        oldRegion = 0L, thumbRegion = 0L, ctlRegion =0L;
  565.     short            diameter;
  566.     
  567.     GetPenState(&oldState);
  568.     PenNormal();
  569.     privData = (PrivateHandle)(*me)->contrlData;
  570.     CalcGrayRect(me, &grayRect, &whiteRect);
  571.     CalcThumbRects(me, (*me)->contrlValue, &thumbRect);
  572.  
  573.     switch (part)
  574.     {
  575.         case 255: // change in dimming
  576.             EraseRect(&grayRect);
  577.         case 0: // draw whole thing
  578.             EraseRect(&whiteRect);
  579.             DrawMyFrame(me,&grayRect);
  580.             DrawMyIndicator(me, &thumbRect);
  581.         break;
  582.         case 129: // redraw generic indicator
  583.                 // I'm using the regions to stop the flashing of drawing 
  584.                 // the gray rect and then drawing the white thumb over it
  585.             oldRegion = NewRgn();
  586.             thumbRegion = NewRgn();
  587.             ctlRegion = NewRgn();
  588.             if (ctlRegion && thumbRegion && oldRegion && privData)
  589.             {
  590.                 diameter = CalcRounding(&(*me)->contrlRect);
  591.                 GetClip(oldRegion);
  592.                 CopyRect(&thumbRect, &tempRect);
  593.                 // InsetRect(&tempRect, -2,-2);
  594.                 OpenRgn();
  595.                     FrameRoundRect(&(*me)->contrlRect, diameter, diameter);
  596.                 CloseRgn(ctlRegion);
  597.                 OpenRgn();
  598.                     FrameRoundRect(&thumbRect, diameter, diameter);
  599.                 CloseRgn(thumbRegion);
  600.                 XorRgn(ctlRegion, thumbRegion, thumbRegion);
  601.                 SetClip(thumbRegion);
  602.                 CleanOldThumb(me, &thumbRect);
  603.                 SetClip(ctlRegion);
  604.                 DrawMyIndicator(me, &thumbRect);
  605.                 SetClip(oldRegion);
  606.             }
  607.             else // we had a memory allocation problem, draw whole thing
  608.             {
  609.                 EraseRect(&whiteRect);
  610.                 DrawMyFrame(me,&grayRect);
  611.                 DrawMyIndicator(me, &thumbRect);
  612.             }
  613.             if (thumbRegion) DisposeRgn(thumbRegion);
  614.             if (ctlRegion) DisposeRgn(ctlRegion);
  615.             if (oldRegion) DisposeRgn(oldRegion);
  616.             break;
  617.         default:
  618.         case inPageUp:
  619.         case inPageDown:
  620.         break;
  621.     }
  622.     if (privData)
  623.         (*privData)->oldValue = (*me)->contrlValue;
  624.     SetPenState(&oldState);
  625. }
  626. /*************** CleanOldThumb *************
  627. ***** We've gotten a message to draw the thumb, which
  628. ***** implies we have to eradicate the old thumb *******/
  629. void CleanOldThumb(ControlHandle me, Rect *thumbRect)
  630. {
  631.     PrivateHandle    privData;
  632.     short            oldValue, currValue;
  633.     short            diameter;
  634.     Rect            grayRect, ctlRect, oldThumb, whiteRect;
  635.     Boolean         upAndDown;
  636.     Pattern            grayPattern;
  637.     
  638.     privData = (PrivateHandle)(*me)->contrlData; // privData has already been tested
  639.     currValue = (*me)->contrlValue;
  640.     oldValue = (*privData)->oldValue;
  641.     
  642.     //if (currValue == oldValue) return;
  643.     
  644.     (*me)->contrlValue = oldValue;
  645.     CalcGrayRect(me, &grayRect, &whiteRect);
  646.     (*me)->contrlValue = currValue;
  647.     
  648.     CopyRect(&(*me)->contrlRect, &ctlRect);
  649.     diameter = CalcRounding(&ctlRect);
  650.     upAndDown = ((ctlRect.right - ctlRect.left) <= (ctlRect.bottom - ctlRect.top));
  651.     
  652.     CalcThumbRects(me, oldValue, &oldThumb);
  653.     GetIndPattern(grayPattern, 0, 1);// black
  654.     PenPat(grayPattern);
  655.  
  656.     if (oldValue > currValue)
  657.     {
  658.         if (upAndDown)
  659.         {
  660.             oldThumb.bottom = thumbRect->bottom;
  661.         }
  662.         else
  663.         {
  664.             oldThumb.left = thumbRect->left;
  665.         }
  666.         FillRoundRect(&oldThumb, diameter, diameter, grayPattern);
  667.     }
  668.     else
  669.     {
  670.         if (upAndDown)
  671.         {
  672.             oldThumb.top = thumbRect->top;
  673.         }
  674.         else
  675.         {
  676.             oldThumb.right = thumbRect->right;
  677.         }
  678.         EraseRoundRect(&oldThumb, diameter, diameter);
  679.     }
  680.     FrameRoundRect(&ctlRect, diameter, diameter);
  681. }
  682. /********** DrawMyIndicator ************
  683. ******* Draw the thumb, the thumbRect must be previously
  684. ******* calculated ******/
  685. void DrawMyIndicator(ControlHandle me, Rect *thumbRect)
  686. {
  687.     Rect        ctlRect;
  688.     Boolean     useColorQD, dimmed = FALSE;
  689.     RGBColor    newColor, oldColor;
  690.     Pattern        grayPattern;
  691.     Boolean        upAndDown;
  692.     short        diameter;
  693.     PrivateHandle    privData;
  694.     
  695.     privData = (PrivateHandle)(*me)->contrlData;
  696.     
  697.     if ((*me)->contrlMin >= (*me)->contrlMax) dimmed = TRUE;
  698.     if ((*me)->contrlHilite == 255) dimmed = TRUE;
  699.     
  700.     
  701.     if (!dimmed)
  702.     {
  703.         CopyRect(&(*me)->contrlRect, &ctlRect);
  704.         diameter = CalcRounding (&ctlRect);
  705.         
  706.     
  707.         // calculate the rectangles used in drawing
  708.         useColorQD = UseColorQD(me, thumbRect);
  709.         // start actual drawing
  710.         if(useColorQD && privData)
  711.         {
  712.             GetForeColor(&oldColor);
  713.             RGBForeColor(&(*privData)->thumbColor);    // real medium gray
  714.             GetIndPattern(grayPattern, 0, 1);// standard black for fill
  715.             FillRoundRect(thumbRect, diameter, diameter, grayPattern);
  716.             RGBForeColor(&oldColor);
  717.         }
  718.         else
  719.         {
  720.             GetIndPattern(grayPattern, 0, 4);// standard gray for fill
  721.             FillRoundRect(thumbRect, diameter, diameter, grayPattern);
  722.         }
  723.         FrameRoundRect(thumbRect, diameter, diameter);
  724.     }
  725. }
  726. /***************** CalcThumbRects ******
  727. **** should be CalcThumbRect, just figure what the bounding rect of
  728. *** the thumb should be given the value *******/
  729. void CalcThumbRects(ControlHandle me, short value, 
  730.         Rect *roundThumb)
  731. {
  732.     long    width, height, thumbLen;
  733.     Point    valuePoint;
  734.     Rect    ctlRect;
  735.     
  736.     CopyRect(&(*me)->contrlRect, &ctlRect);
  737.     CopyRect(&ctlRect, roundThumb);
  738.     
  739.     height = ctlRect.bottom - ctlRect.top;
  740.     width = ctlRect.right - ctlRect.left;
  741.     
  742.     MapValue2Point(me, value, &valuePoint);
  743.     thumbLen = CalcThumbLen(&ctlRect);
  744.     // calculate the rectangles used in drawing
  745.     if (height >= width)
  746.     {
  747.         roundThumb->top = valuePoint.v - thumbLen/2;
  748.         roundThumb->bottom = roundThumb->top+thumbLen;
  749.         
  750.     }
  751.     else
  752.     {
  753.         roundThumb->right = valuePoint.h + thumbLen/2;
  754.         roundThumb->left = roundThumb->right - thumbLen;
  755.     }
  756. }
  757. /********** CalcThumbLen *********
  758. **** figure how high or wide the thumb should be (given
  759. **** that some moron might have made the control too small ***/
  760. short CalcThumbLen(Rect *ctlRect)
  761. {
  762.     short    height, width;
  763.     short    result;
  764.     height = ctlRect->bottom - ctlRect->top;
  765.     width = ctlRect->right - ctlRect->left;
  766.     if (width > height)
  767.     {
  768.         result = (width > 20)?20:width;
  769.     }
  770.     else
  771.     {
  772.         result = (height > 20)?20:height;
  773.     }
  774.     return (result);
  775. }
  776. /********* DrawMyFrame **********
  777. ******* Draw the black portion of the control (pageup)
  778. ******* and frame the whole thing ********/
  779. void DrawMyFrame(ControlHandle me, Rect *grayRect)
  780. {    
  781.     Rect        ctlRect;
  782.     Boolean     useColorQD, dimmed = FALSE;
  783.     RGBColor    newColor, oldColor;
  784.     Pattern        grayPattern;
  785.     PrivateHandle    privData;
  786.     short         min, max, diameter;
  787.     privData = (PrivateHandle)(*me)->contrlData;
  788.     
  789.     CopyRect(&(*me)->contrlRect, &ctlRect);
  790.     useColorQD = UseColorQD(me, &ctlRect);
  791.     min = (*me)->contrlMin;
  792.     max = (*me)->contrlMax;
  793.     diameter = CalcRounding (&ctlRect);
  794.     if (min >= max) 
  795.     {
  796.         dimmed = TRUE;
  797.     }
  798.     if ((*me)->contrlHilite == 255) dimmed = TRUE;
  799.     
  800.     if (!dimmed)
  801.     {
  802.         GetIndPattern(grayPattern, 0, 1);// standard black for frame and top region
  803.         FillRoundRect(grayRect,diameter, diameter, grayPattern);
  804.         PenPat(grayPattern);
  805.     }
  806.  
  807.     FrameRoundRect(&ctlRect, diameter, diameter);
  808. }
  809. /*********** CalcGrayRect
  810. ***** figure out the rectangle which enclose the pageup and pagedown
  811. ***** parts of the control (they meet in the middle of the thumb) ***/
  812. void    CalcGrayRect(ControlHandle me, Rect *grayRect, Rect *whiteRect)
  813. {
  814.     long    height, width, value, max, min;
  815.     Point    valuePoint;  
  816.     short    thumbLen, halfThumb;
  817.     
  818.     
  819.     value = (*me)->contrlValue;
  820.     min = (*me)->contrlMin;
  821.     max = (*me)->contrlMax;
  822.     if (value > max) // too big, who let this in?
  823.         value = max;
  824.     else if (value < min) // too small
  825.         value = min;
  826.     MapValue2Point(me,value, &valuePoint);
  827.     
  828.     CopyRect(&(*me)->contrlRect, grayRect);
  829.     CopyRect(grayRect, whiteRect);
  830.     thumbLen = CalcThumbLen(grayRect);
  831.     halfThumb = thumbLen /2;
  832.     width = grayRect->right - grayRect->left;
  833.     height = grayRect->bottom - grayRect->top;
  834.     if (width > height) // we are going side to side
  835.     {
  836.         grayRect->left = valuePoint.h - halfThumb;
  837.         whiteRect->right = valuePoint.h;
  838.     }
  839.     else
  840.     { // halfThumb is because quickdraw sort of bales out
  841.         // when round rects are small 
  842.         grayRect->bottom = valuePoint.v + halfThumb;
  843.         whiteRect->top = valuePoint.v;
  844.     }
  845. }
  846. /******* CalcRounding *******
  847. ****** are we big enough to use round rectangles 
  848. if so use 16 diameter rounding, if not use square corners ****/
  849. short CalcRounding(Rect *ctlRect)
  850. {
  851.     short    width, height;
  852.     width = ctlRect->right - ctlRect->left;
  853.     height = ctlRect->bottom - ctlRect->top;
  854.     if (width > height)
  855.     {
  856.         if (width > 64)
  857.             return (16);
  858.     }
  859.     else
  860.     {
  861.         if (height > 64)
  862.             return (16);
  863.     }
  864.     return (0);
  865. }
  866.  
  867. /******** InitMe ********
  868. ****** allocate my global memory, test for color and load color table
  869. ****** information ****/
  870. void InitMe(ControlHandle me)
  871. {
  872.     PrivateHandle    privDataH;
  873.     AuxCtlHandle        acHndl;
  874.     CCTabHandle        tableH;
  875.     short            tabLen;
  876.     RGBColor        *tempColor;
  877.     privDataH = (PrivateHandle)NewHandleClear(sizeof(Private));
  878.     if (privDataH)
  879.     {
  880.  
  881.         if ((*privDataH)->useColorQD = TestForColor())
  882.         {// we are using color, find the highlight color
  883.  
  884.             tempColor = &(*privDataH)->thumbColor; 
  885.             tempColor->blue = tempColor->green = tempColor->red = 30583; // gray
  886.             GetAuxCtl(me, &acHndl);
  887.             if (acHndl)
  888.             {
  889.                 tableH = (*acHndl)->acCTable;
  890.                 tabLen = (*tableH)->ctSize;
  891.                 while(tabLen >= 0)
  892.                 {
  893.                 /*    if ((*tableH)->ctTable[tabLen].value == cThumbColor)
  894.                     {
  895.                         BlockMove(&(*tableH)->ctTable[tabLen].rgb, 
  896.                             &(*privDataH)->thumbColor, sizeof(RGBColor));
  897.                     } */
  898.                     tabLen--;
  899.                 }
  900.             }
  901.         }
  902.         // we need to know if we can call GetDeviceList to tell whether 
  903.         // or not our control is on a deep color screen
  904.         (*privDataH)->devicesAvailable = TrapAvailable(0xAA29);
  905.         
  906.         (*privDataH)->oldValue = (*me)->contrlValue;
  907.     }
  908.     (*me)->contrlData = (Handle)privDataH;
  909. }